﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Text;
using Baddies.Utils;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Baddies.Map
{
    /// <summary>
    /// A Map tile, holds all the properties of that specific area of the map.
    /// </summary>
    public class MapTile
    {
        /// <summary>
        /// If the tile is visible or not.
        /// </summary>
        private bool visible;

        /// <summary>
        /// If characters can walk on this tile.
        /// </summary>
        private bool walkable;

        /// <summary>
        /// Position of the tile in the map. Measured in pixels.
        /// </summary>
        private Rectangle mapArea;

        /// <summary>
        /// Position of the tile in the map in row/col.
        /// </summary>
        private Vector2 tilePos;

        /// <summary>
        /// Area of the material used in the tile.
        /// </summary>
        private Rectangle materialArea;

        /// <summary>
        /// Rectangle for drawing.
        /// </summary>
        private Rectangle drawRect;

        /// <summary>
        /// Gets or sets a value indicating whether the tile is visible or not.
        /// </summary>
        /// <value>True if it's visible, false otherwise.</value>
        public bool Visible
        {
            get { return this.visible; }
            set { this.visible = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the tile can be walked on or not.
        /// </summary>
        /// <value>True if it can be walked on, false otherwise.</value>
        public bool Walkable
        {
            get { return this.walkable; }
            set { this.walkable = value; }
        }

        /// <summary>
        /// Gets or sets he mapArea of the tile.
        /// </summary>
        /// <value>Area of the tile in the map.</value>
        public Rectangle MapArea
        {
            get { return this.mapArea; }
            set { this.mapArea = value; }
        }

        /// <summary>
        /// Gets or sets the materialArea of the tile (texture wise).
        /// </summary>
        /// <value>Area of the material we need.</value>
        public Rectangle MaterialArea
        {
            get { return this.materialArea; }
            set { this.materialArea = value; }
        }

        /// <summary>
        /// Gets or sets the tile position in the map col / row.
        /// </summary>
        /// <value>Tile position in col/row format.</value>
        public Vector2 TilePos
        {
            get { return this.tilePos; }
            set { this.tilePos = value; }
        }

        /// <summary>
        /// Initializes a new instance of the MapTile class.
        /// </summary>
        /// <param name="tilex">X position of the tile (row).</param>
        /// <param name="tiley">Y position of the tile (col).</param>
        /// <param name="tileSize">Size of the tile.</param>     
        public MapTile(int tilex, int tiley, int tileSize)
        {
            this.visible = true;
            this.walkable = true;

            this.SetMapPosition(tilex, tiley, tileSize);

            // Create rectangle for drawing.
            this.drawRect = new Rectangle();
            this.drawRect.Width = tileSize;
            this.drawRect.Height = tileSize;
        }

        /// <summary>
        /// Initializes a new instance of the MapTile class.
        /// </summary>  
        public MapTile()
        {
            this.visible = true;
            this.walkable = true;

            this.tilePos = new Vector2();
            this.tilePos.X = 0;
            this.tilePos.Y = 0;

            // Create the rectangle to keep the position of the tile in the map
            this.mapArea = new Rectangle();
            this.mapArea.Width = 16;
            this.mapArea.Height = 16;
            this.mapArea.X = 0;
            this.mapArea.Y = 0;

            // Create rectangle for drawing.
            this.drawRect = new Rectangle();
            this.drawRect.Width = 16;
            this.drawRect.Height = 16;
        }

        /// <summary>
        /// Sets or resets the position of the tile on the map.
        /// </summary>
        /// <param name="tilex">X position of the tile (row).</param>
        /// <param name="tiley">Y position of the tile (col).</param>
        /// <param name="tileSize">Size of the tile.</param>  
        public void SetMapPosition(int tilex, int tiley, int tileSize)
        {
            this.tilePos = new Vector2();
            this.tilePos.X = tilex;
            this.tilePos.Y = tiley;

            // Create the rectangle to keep the position of the tile in the map
            this.mapArea = new Rectangle();
            this.mapArea.Width = tileSize;
            this.mapArea.Height = tileSize;
            this.mapArea.X = tilex * tileSize;
            this.mapArea.Y = tiley * tileSize;
        }

        /// <summary>
        /// Sets the region of the parent texture we shall use to draw.
        /// </summary>
        /// <param name="materialArea">Area of the tilemap texture for the terrain that corresponds to this tile.</param>
        public void SetDrawTexture(Rectangle materialArea)
        {
            this.materialArea = materialArea;
        }

        /// <summary>
        /// Draws the tile.
        /// </summary>
        /// <param name="spritebatch">Spritebatch to draw on.</param>
        /// <param name="tileSet">Tileset image that the tiles will use to draw.</param>
        /// <param name="drawPosition">Parent position, for displacement.</param>
        public void DrawTerrain(SpriteBatch spritebatch, Texture2DProxy tileSet, Vector3 drawPosition)
        {
            this.drawRect.X = this.mapArea.X + (int)drawPosition.X;
            this.drawRect.Y = this.mapArea.Y + (int)drawPosition.Y;

            spritebatch.Draw(tileSet.Texture, this.drawRect, this.materialArea, Color.White);
        }

        /// <summary>
        /// Draws the tile collision.
        /// </summary>
        /// <param name="spritebatch">Spritebatch to draw on.</param>
        /// <param name="drawPosition">Parent position, for displacement.</param>
        public void DrawCollision(SpriteBatch spritebatch, Vector3 drawPosition)
        {
            this.drawRect.X = this.mapArea.X + (int)drawPosition.X;
            this.drawRect.Y = this.mapArea.Y + (int)drawPosition.Y;
        }

        /// <summary>
        /// Draws the tile grid.
        /// </summary>
        /// <param name="spritebatch">Spritebatch to draw on.</param>
        /// <param name="gridTexture">Texture to use to draw the grid.</param>
        /// <param name="drawPosition">Parent position, for displacement.</param>
        public void DrawGrid(SpriteBatch spritebatch, Texture2D gridTexture, Vector3 drawPosition)
        {
            this.drawRect.X = this.mapArea.X + (int)drawPosition.X;
            this.drawRect.Y = this.mapArea.Y + (int)drawPosition.Y;

            // Draw the 4 lines
            spritebatch.Draw(gridTexture, new Rectangle(this.drawRect.X, this.drawRect.Y, this.drawRect.Width, 1), Color.Red);
            spritebatch.Draw(gridTexture, new Rectangle(this.drawRect.X, this.drawRect.Y, 1, this.drawRect.Height), Color.Red);
            spritebatch.Draw(gridTexture, new Rectangle(this.drawRect.X, this.drawRect.Y + this.drawRect.Height, this.drawRect.Width, 1), Color.Red);
            spritebatch.Draw(gridTexture, new Rectangle(this.drawRect.X + this.drawRect.Width, this.drawRect.Y, 1, this.drawRect.Height), Color.Red);
        }

        /// <summary>
        /// Gets a string representation of the class.
        /// </summary>
        /// <returns>String representation of the class.</returns>
        public override string ToString()
        {
            return "Tile: " + this.tilePos;
        }
    }
}
